using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Delete;
using Magiq.Insert;
using Magiq.Behaviors;
using Magiq.Query;
using Magiq.Update;

namespace Magiq
{
    public class MagiqOperations<T> : IMagiq<T> where T : class
    {
        private readonly IEnumerable<T> collection;
        private readonly IMagiqBehavior behaviorChain;

        public MagiqOperations(IEnumerable<T> collection, IMagiqBehavior behaviorChain)
        {
            this.collection = collection;
            this.behaviorChain = behaviorChain;
        }

        public IUpdate<T> Set<TReturn>(Expression<Func<T, TReturn>> property, TReturn value)
        {
            return new Update<T>(collection, behaviorChain).Set(property, value);
        }

        public IUpdate<T> Set<TReturn>(Expression<Func<T, TReturn>> property, Expression<Func<T, TReturn>> value)
        {
            return new Update<T>(collection, behaviorChain).Set(property, value);
        }

        public int Delete()
        {
            return new Delete<T>(collection, behaviorChain).Execute();
        }

        public int Delete(Expression<Func<T, bool>> where)
        {
            return collection.Query(where).Delete();
        }

        public IInsertBuilder<TSource, T> From<TSource>(IEnumerable<TSource> source)
        {
            return new InsertBuilder<TSource, T>(source, collection, behaviorChain);
        }

        public IQueryable<T> Query()
        {
            if (collection is IQueryable<T>)
                return (IQueryable<T>) collection;

            return new Query<T>(collection, behaviorChain).Execute();
        }

        public IQueryable<T> Query(Expression<Func<T, bool>> where)
        {
            if (collection is IQueryable<T>)
                return (IQueryable<T>) collection;

            return Query().Where(where);
        }

        public IMagiq<T> Using(IMagiqBehavior behavior)
        {
            behaviorChain.NextBehavior = behavior;
            return this;
        }

        public IMagiq<T> Using<TBehavior>() where TBehavior : IMagiqBehavior, new()
        {
            return Using<TBehavior>(x => { });
        }

        public IMagiq<T> Using<TBehavior>(Action<TBehavior> configureBehavior) where TBehavior : IMagiqBehavior, new()
        {
            var behavior = new TBehavior();
            configureBehavior(behavior);
            behaviorChain.NextBehavior = behavior;
            return this;
        }
    }
}